package gew.services;

import gew.data.LoadRequest;
import gew.utils.SqlUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import static java.net.HttpURLConnection.HTTP_OK;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;

public abstract class TradeImportData {

    public static Integer getFilesCount(String folder, String fileExtension) {
        File dir = new File(folder);
        String[] archives
                = dir.list(new FilenameFilter() {
                    @Override
                    public boolean accept(File dir, String name) {
                        return name.endsWith(fileExtension);
                    }
                });
        return archives.length;
    }

    public static String getFileName(String folder, String fileExtension) {
        File dir = new File(folder);
        String[] archives
                = dir.list(new FilenameFilter() {
                    @Override
                    public boolean accept(File dir, String name) {
                        return name.endsWith(fileExtension);
                    }
                });
        if (archives.length == 0) {
            return null;
        }
        return archives[0];
    }

    public static boolean extractArchive(String filename, String resultfileName, String foldername, Integer extractTimeout, Integer extractSleepStep) {
        try {
            String cmdExtract = "7z e "
                    .concat(foldername)
                    .concat(filename);
            String cmdMove = "mv "
                    .concat(resultfileName)
                    .concat(SqlUtils.SPACE)
                    .concat(foldername)
                    .concat(resultfileName);
            Process p = Runtime.getRuntime().exec(cmdExtract);
            Integer t = 0;
            while (p.isAlive() && t <= extractTimeout) {
                Thread.sleep(extractSleepStep);
                t += extractSleepStep;
            }
            p = Runtime.getRuntime().exec(cmdMove);
            t = 0;
            while (p.isAlive() && t <= extractTimeout) {
                Thread.sleep(extractSleepStep);
                t += extractSleepStep;
            }
            p.destroy();
            return true;
        } catch (Exception e) {
            System.out.println("***** EXCEPTION on extractArchive *****");
            System.out.println(e.getMessage());
            return false;
        } finally {
            Runtime.getRuntime().gc();
        }
    }

    public static boolean removeFile(String filename, String foldername, Integer timeout, Integer sleepStep) {
        try {
            String cmd = "rm ".concat(foldername).concat(filename);
            Process p = Runtime.getRuntime().exec(cmd);
            Integer t = 0;
            while (p.isAlive() && t <= timeout) {
                Thread.sleep(sleepStep);
                t += sleepStep;
            }
            p.destroy();
            return true;
        } catch (Exception e) {
            System.out.println("***** EXCEPTION on removeFile *****");
            System.out.println(e.getMessage());
            return false;
        } finally {
            Runtime.getRuntime().gc();
        }
    }

    public static boolean moveFile(String filename, String sourceFoldername, String destinationFoldername, Integer timeout, Integer sleepStep) {
        try {
            String cmd = "mv "
                    .concat(sourceFoldername)
                    .concat(filename)
                    .concat(SqlUtils.SPACE)
                    .concat(destinationFoldername)
                    .concat(filename);
            Process p = Runtime.getRuntime().exec(cmd);
            Integer t = 0;
            while (p.isAlive() && t <= timeout) {
                Thread.sleep(sleepStep);
                t += sleepStep;
            }
            p.destroy();
            return true;
        } catch (Exception e) {
            System.out.println("***** EXCEPTION on moveFile *****");
            System.out.println(e.getMessage());
            return false;
        } finally {
            Runtime.getRuntime().gc();
        }
    }

    public static boolean createArchive(String filename, String sourceFoldername, String archiveFileName, String destinationFoldername, Integer timeout, Integer sleepStep) {
        try {
            String cmd = "7z a -t7z "
                    .concat(destinationFoldername).concat(archiveFileName)
                    .concat(SqlUtils.SPACE)
                    .concat(sourceFoldername).concat(filename);
            Process p = Runtime.getRuntime().exec(cmd);
            Integer t = 0;
            while (p.isAlive() && t <= timeout) {
                Thread.sleep(sleepStep);
                t += sleepStep;
            }
            p.destroy();
            return true;
        } catch (IOException | InterruptedException e) {
            System.out.println("***** EXCEPTION on createArchive *****");
            System.out.println(e.getMessage());
            return false;
        } finally {
            Runtime.getRuntime().gc();
        }
    }

    public static boolean importFileData2(String filename, String foldername, QueryService queryService, Integer loadRequestId) {
        boolean result = true;
        try {
            // Создать временную таблицу для хранения данных загруженного файла
            // Создать таблицу для заполнения только кодами и ключами
            // Загрузить данные из файла во временную таблицу
            // Удалить временную таблицу для хранения данных загруженного файла
            // Записать в LoadRequest количество необработанных строк
            // Заполнить таблицу с кодами и ключами
            // Выстроить в таблице с кодами и ключами индексы
            // Подготовить данные для вставки в таблицу фактов
            System.out.println(loadRequestId.toString() + " ***** PREPARATION ***** ");
            result = queryService.tradeLoadPreparation(loadRequestId, foldername.concat(filename));
            if (!result) {
                return result;
            }

            // Проверить наличие в таблице фактов партиций, соответствующих новым данным
            // Если каких-либо партиций нет - создать их
            // Получить набор запросов для удаления устаревших данных из таблицы fct_trade
            // Выполнить этот набор запросов (в вызываемой процедуре)
            // Вставить новые записи в fct_trade
            // Удалить временную таблицу для хранения данных загруженного файла (id)
            System.out.println(loadRequestId.toString() + " *****  EXECUTION  ***** ");
            result = queryService.tradeLoadExecution(loadRequestId);
            if (!result) {
                return result;
            }

            System.out.println(loadRequestId.toString() + " DB procedures completed");
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static int createNewLocalLoadRequest(String filename, QueryService queryService, Integer status) {
        try {
            return queryService.insertLocalLoadRequest(filename, status);
        } catch (Exception e) {
            System.out.println("***** EXCEPTION on createNewLocalLoadRequest *****");
            System.out.println(e.getMessage());
            return -1;
        }
    }

    public static Integer getCreatedLocalLoadRequestId(String filename, QueryService queryService, Integer status, Integer idError) {
        try {
            LoadRequest loadRequest = queryService.getNextLoadRequest(filename, status);
            if (loadRequest == null) {
                return -1;
            }
            return loadRequest.getLoadRequestId();
        } catch (Exception e) {
            System.out.println("***** EXCEPTION on getCreatedLocalLoadRequest *****");
            System.out.println(e.getMessage());
            return idError;
        }
    }

    public static LoadRequest getNextLoadRequest(QueryService queryService, Integer status) {
        try {
            LoadRequest loadRequest = queryService.getNextLoadRequest(status);
            return loadRequest;
        } catch (Exception e) {
            System.out.println("***** EXCEPTION on getCreatedLocalLoadRequest *****");
            System.out.println(e.getMessage());
            return null;
        }
    }

    public static boolean updateLoadRequestStatus(QueryService queryService, Integer loadRequestId, Integer status) {
        try {
            queryService.updateLoadRequestStatus(loadRequestId, status);
            return true;
        } catch (Exception e) {
            System.out.println("***** EXCEPTION on changeLoadRequestStatus *****");
            System.out.println(e.getMessage());
            return false;
        }
    }

    public static boolean checkUrlAvailability(String url) {
        Boolean isReachable = false;
        try {
            HttpURLConnection huc = (HttpURLConnection) (new URL(url)).openConnection();
            huc.setRequestMethod("GET");
            huc.connect();
            isReachable = huc.getResponseCode() == HTTP_OK;
        } catch (UnknownHostException ex) {
            System.out.println(ex.getMessage());
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
        return isReachable;
    }

    public static boolean loadFileFromUrl(String foldername, String filename, String url, Integer bufferSize) {
        String localFileName = foldername.concat(filename);
        try {
            HttpURLConnection huc = (HttpURLConnection) (new URL(url)).openConnection();
            InputStream is = huc.getInputStream();
            FileOutputStream fos = new FileOutputStream(localFileName);
            int bytesRead = -1;
            byte[] buffer = new byte[bufferSize];
            while ((bytesRead = is.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
            fos.close();
            is.close();
            return true;
        } catch (MalformedURLException e) {
            System.out.println(e.getMessage());
            return false;
        } catch (IOException e) {
            System.out.println(e.getMessage());
            return false;
        }
    }

}
